package particleField;

import java.awt.Stroke;
import java.awt.print.Paper;
import java.util.ArrayList;

import javax.media.opengl.GL;
import javax.sound.sampled.Line;

import SimpleOpenNI.SimpleOpenNI;


import processing.core.*;
import processing.opengl.PGraphicsOpenGL;

public class ParticleSystem {

	ArrayList<Particle> particles; // An arraylist for all the particles
	PVector origin; // An origin point for where particles are born
	PVector[][] magneticField;
	float a;
	private int numberOfThreads = 8;
	private int numberOfParticles; //per Thread
	ParticlePositionThread partpos_thread;
	SimpleOpenNI context;

	public ParticleSystem(int num, PVector v, PApplet pa, SimpleOpenNI context) {
		particles = new ArrayList<Particle>(); // Initialize the arraylist
		origin = v.get(); // Store the origin point
		magneticField = new PVector[(int)v.x][(int)v.y];
		resetMagField();
		this.context = context;

		
		for (int x = 10; x < v.x; x+= 3) {
			for (int y = 10; y < v.y; y+=3) {
				addParticle(x, y);

			}			
		}
		System.out.println("Anzahl Partikel: " + particles.size());
		numberOfParticles = particles.size()/numberOfThreads;
		System.out.println("Partikel pro Thread: "+numberOfParticles);
		for(int i=0; i<numberOfThreads; i++){
			Thread t = new Thread(new ParticleUpdate(pa, particles.subList(i*numberOfParticles, (i+1)*numberOfParticles)));
			t.start();
		}
		
		partpos_thread = new ParticlePositionThread(context, particles);
		Thread partPos_thread = new Thread(partpos_thread );
		partPos_thread.start();
	}

	public void resetMagField() {
		for (int i = 0; i < magneticField.length; i++) {
			for (int j = 0; j < magneticField[0].length; j++) {
//				float t1 = (float)( ((i*1.0)/(float)magneticField.length)*2*Math.PI);
//				float t2 = (float)((j*1.0/(float)magneticField[0].length)*2*Math.PI);
				magneticField[i][j] = new PVector();
			}			
		}
	}

	public void run(PApplet pa) {
		// Cycle through the ArrayList backwards b/c we are deleting
//		long start = System.currentTimeMillis();
		PGraphicsOpenGL glb = (PGraphicsOpenGL) pa.g;
		GL gl = glb.beginGL();
		
		for (int i = particles.size() - 1; i >= 0; i--) {
			Particle p = (Particle) particles.get(i);
			
			gl.glColor3f( 1, 1, 1);
//			gl.glColor3f( pa.red(p.color), pa.green(p.color), pa.blue(p.color));
			gl.glRectf(p.loc.x, p.loc.y, p.loc.x+p.velo_height, p.loc.y+p.velo_height);
		}

		glb.endGL();
//		long stop = System.currentTimeMillis();
//		System.out.println(stop-start);
		
	}

	public void force_home() {
		for (Particle elem : particles) {
			elem.force_home();
		}
	}

	public void force_disable_home() {
		for (Particle elem : particles) {
			elem.force_disable_home();
		}
	}
	
	public void add_magnet(PApplet pa, PVector mag, int radius, boolean magnetic){
		mag = new PVector(mag.x, mag.y);
		
		int beg_y = 0;
		int beg_x = 0;
		
//		if(mag.y - radius >= 0 && mag.x - radius >= 0 ){
//			beg_y = (int) (mag.y - radius);
//			beg_x = (int) (mag.x - radius);
//		}
		
		
		for (int i = beg_x; i < magneticField.length /*&& i < (beg_x+2*radius)*/; i++) {
			for (int j = beg_y; j < magneticField[0].length  /*&& j < (beg_y+2*radius)*/; j++) {
//				pa.ellipse(i, j, 1, 1);
				float dist = mag.dist( new PVector(i, j));
				if( dist < radius){
					PVector tmp = PVector.sub( new PVector(i, j), mag);
					tmp.mult((float) (((1-dist/radius))*0.2) );
					if(magnetic) tmp.mult(-1);
					magneticField[i][j].set(tmp);
					magneticField[i][j].normalize();
					magneticField[i][j].mult(0.5f);

				}
			}			
		}
		
	}
	

	
	
//	public void addForceDirection(SimpleOpenNI context){
//
//		int userCount = context.getNumberOfUsers();
//		int[] userMap = null;
//		if (userCount > 0) {
//			userMap = context.getUsersPixels(SimpleOpenNI.USERS_ALL);
//		}
//
//		int[][] usermap_2d = null;
//		usermap_2d = new int[context.depthWidth()][context.depthHeight()];
//		if (userCount > 0) {
//			userMap = context.getUsersPixels(SimpleOpenNI.USERS_ALL);	
//			
//			int width = context.depthWidth();
//			for (int i = 0; i < userMap.length; i++) {
//				int x = i % width;
//				int y = i / width;
//				
//				usermap_2d[x][y] = userMap[i];
//			}
//
//			
//		}
//		for (Particle elem : particles) {
//			if(userMap!=null){
//				int x_part = (int)(elem.loc.x/2);
//				int y_part = (int)(elem.loc.y/2);
//				int index = x_part+y_part*context.depthWidth();
//				if( index > 0 && index <userMap.length-1 && userMap[(x_part+y_part*context.depthWidth())-1] != 0 ){
//
//						if(elem.inUserArray == false){
//							double angle = escapeAngle(usermap_2d, x_part, y_part, context.depthWidth());
//							angle = angle/360*2*Math.PI;
//							PVector tmp = new PVector( (float)Math.cos(angle), (float)Math.sin(angle));
//							tmp.normalize();
//							tmp.mult(5f);
//							elem.vel.add( tmp);
//							elem.inUserArray = true;
//							elem.color = 0xFFFFFFFF;
//						}else{
//							elem.vel.normalize();
//							elem.vel.mult(5f);
//							elem.color = 0xFFFF0000;
//						}
//
//					}else{
//						if(elem.inUserArray == true){
//							elem.vel.normalize();
//							elem.inUserArray = false;
//							elem.color = 0xFFFFFFFF;
//						}
//						
//					}
//				
//				
//			}
//		}
//		
//
//	}
//	
//
//
//	
//	public double escapeAngle(int[][] array, int x, int y, int width_p){
//		int maxRadius = 20;
//		int width = array.length;
//		int height = array[0].length;
//		for (int i = 1; i < maxRadius; i++) {
//			
//			if(x+i < width && y+i < height && x-i >= 0 && y-i >= 0){
//				int n = array[x][y-i];
//				int w = array[x-i][y];
//				int e = array[x+i][y];
//				int s = array[x][y+i];
//				int nw = array[x-i][y-i];
//				int ne = array[x+i][y-i];
//				int se = array[x+i][y+i];
//				int sw = array[x-i][y+i];
//				
//				if(s == 0){
//					return 90;
//				}else if(w == 0){
//					return 180;
//				}else if(n == 0){
//					return 270;
//				}else if(e == 0){
//					return 0;
//				}else if(nw == 0){
//					return 225;
//				}else if(ne == 0){
//					return 315;
//				}else if(sw == 0){
//					return 135;
//				}else if(se == 0){
//					return 45;
//				}
//			}
//
//
//			
//		}
//
//		return Math.random()*360;
//	}
	
	public void gravity() {
		for (Particle elem : particles) {
			elem.vel.add(0, 1, 0);		
		}
	}
	
	private boolean isInRange(int x, int beg, int end){
		if( x >= 0 && x < end){
			return true;
		}else{
			return false;
		}
	}



	private void addParticle(float x, float y) {		
			particles.add(new Particle(new PVector(x, y), magneticField));
	}

	void addParticle(Particle p) {
		particles.add(p);
	}

	// A method to test if the particle system still has particles
	boolean dead() {
		if (particles.isEmpty()) {
			return true;
		} else {
			return false;
		}
	}
	
	
	public void loadDirectionPic(PApplet pa){
		PImage img = pa.loadImage("dir02.png");
		System.out.println("Bildgroesse: "+img.width+"*"+img.height);
		System.out.println("MagneticField groesse: "+magneticField.length+"*"+magneticField[0].length);
		
		for (int i = 0;  i < img.width; i+= 1) {
			for (int j = 0; j < img.height; j+= 1) {
				
				int gray = img.get(i, j);
				if(gray != 0xFFFFFFFF ){
					magneticField[i][j] = new PVector( (float)Math.cos( (gray&0xFF)/255.0*2*Math.PI), (float)Math.sin( (gray&0xFF)/255.0*2*Math.PI) );
					magneticField[i][j].mult(0.05f);
				}
				
				
			}
		}
	}
}